﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using DotNetNeural.Data.Base;
using DotNetNeural.Data.Utils;
using DotNetNeural.Visualisation.Data;

namespace DotNetNeural.Visualisation
{
    /// <summary>
    /// Interaction logic for HoneyCombControl.xaml
    /// </summary>
    public partial class HoneycombControl : UserControl, ISurface
    {
        #region Dependency properties

        #region Cell size

        public static readonly DependencyProperty CellSizeProperty =
            DependencyProperty.Register("CellSize", typeof(float), typeof(HoneycombControl),
            new PropertyMetadata(25f, OnCellSizeChangedCallback));

        public float CellSize
        {
            get
            {
                return (float)GetValue(CellSizeProperty);
            }
            set
            {
                SetValue(CellSizeProperty, value);
            }
        }

        private static void OnCellSizeChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HoneycombControl control = d as HoneycombControl;
            if (control != null)
            {
                control.Redraw();
            }
        }

        #endregion

        #region Virtual size

        public static readonly DependencyProperty VirtualSizeProperty =
            DependencyProperty.Register("VirtualSize", typeof(Size), typeof(HoneycombControl),
            new PropertyMetadata(new Size(1000,1000), OnVirtualSizeChanged));

        public Size VirtualSize
        {
            get
            {
                return (Size)GetValue(VirtualSizeProperty);
            }
            set
            {
                SetValue(VirtualSizeProperty, value);
            }
        }

        private static void OnVirtualSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            HoneycombControl control = d as HoneycombControl;
            if (control == null)
                return;

            control.Redraw();
        }


        #endregion

        #endregion

        public HoneycombControl()
        {
            InitializeComponent();

            SizeChanged += new SizeChangedEventHandler(HoneyCombControl_SizeChanged);

            points = new List<HoneycombPoint>();
            sequence = new IntSequence();
        }

        #region ISurface Members

        public void AddPoint(Point2D point, object value)
        {
            Point2D controlCoordinates = TranslateToControl(point);
            var hit = VisualTreeHelper.HitTest(LayoutRoot, new Point(controlCoordinates.X, controlCoordinates.Y));
            if (hit != null && hit.VisualHit != null)
            {
                var hitControl = hit.VisualHit;
                HoneycombCellControl cell = FindParent<HoneycombCellControl>(hitControl);
                if (cell != null)
                {
                    HoneycombPoint hPoint = new HoneycombPoint(sequence.Next(), value, point);
                    //TODO add point and value to found cell

                    points.Add(hPoint);
                }
            }
        }

        public void RemovePoint(Point2D point)
        {
            throw new NotImplementedException();
        }

        public object GetValueAt(Point2D point)
        {
            throw new NotImplementedException();
        }

        List<HoneycombPoint> points;
        IntSequence sequence;

        #endregion

        #region Protected methods

        protected void Redraw()
        {
            Draw(CellSize);
            AssignPointsToCells();

            //
        }

        /// <summary>
        /// Draws empty cells on control
        /// </summary>
        protected void Draw(float sizeBase)
        {
            if (sizeBase < 25)
                sizeBase = 25;

            LayoutRoot.Children.Clear();

            Size controlSize = this.RenderSize;

            float h = (float)(controlSize.Width / sizeBase);

            float i = 0;
            float j = 0;

            while (j * sizeBase < controlSize.Height + sizeBase / 2)
            {
                i = 0;

                while (((3 * i) / 2) * sizeBase < controlSize.Width + sizeBase / 2)
                {

                    float x = ((3 * i) / 2) * sizeBase;

                    HoneycombCellControl item = new HoneycombCellControl()
                    {
                        Width = sizeBase,
                        Height = sizeBase
                    };
                    LayoutRoot.Children.Add(item);

                    Canvas.SetTop(item, sizeBase * j);
                    Canvas.SetLeft(item, x);

                    i += 1;
                }

                j += 1;
            }


            j = -1;

            while (j * sizeBase < controlSize.Height - sizeBase/2)
            {
                i = -1;

                while (((3 + 6 * i) / 4) * sizeBase < controlSize.Width)
                {
                    float x = ((3 + 6 * i) / 4) * sizeBase;

                    HoneycombCellControl item = new HoneycombCellControl()
                    {
                        Width = sizeBase,
                        Height = sizeBase
                    };
                    LayoutRoot.Children.Add(item);

                    Canvas.SetTop(item, sizeBase / 2 + sizeBase * j);
                    Canvas.SetLeft(item, x);

                    i += 1;
                }

                j += 1;
            }
        }

        /// <summary>
        /// Assigns points to each cell in control
        /// </summary>
        protected void AssignPointsToCells()
        {
            //TODO
        }

        protected Point2D TranslateToControl(Point2D virtualPoint)
        {

            float ratio = virtualPoint.X / (float)VirtualSize.Width;
            float cx = (float)LayoutRoot.ActualWidth * ratio;

            ratio = virtualPoint.Y / (float)VirtualSize.Height;
            float cy = (float)LayoutRoot.ActualHeight - (float)LayoutRoot.ActualHeight * ratio;

            return new Point2D(cx, cy);
        }

        #endregion

        #region Private methods

        private void HoneyCombControl_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            Redraw();
        }

        private T FindParent<T>(DependencyObject child) where T : DependencyObject
        {
            var parent = VisualTreeHelper.GetParent(child);

            if (parent == null)
                return null;

            if (parent != null && parent.GetType() == typeof(T))
                return parent as T;
            else
                return FindParent<T>(parent);
        }

        #endregion

    }
}
